417. 太平洋大西洋水流问题

链接:https://leetcode-cn.com/problems/pacific-atlantic-water-flow/

题目描述

给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示:
输出坐标的顺序不重要
m 和 n 都小于150
示例:
给定下面的 5x5 矩阵:

1
2
3
4
5
6
7
太平洋 ~   ~   ~   ~   ~ 
~ 1 2 2 3 (5) *
~ 3 2 3 (4) (4) *
~ 2 4 (5) 3 1 *
~ (6) (7) 1 4 5 *
~ (5) 1 1 2 4 *
* * * * * 大西洋

返回:

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).

分析

首先拿到这道题很明显能够判断出是一个二维平面回溯算法的题目,所以首先我们要准备一个移动坐标:

1
2
# 分别表示上右下左
self.directs = [(-1, 0), (0, 1), (1, 0), (0, -1)]

一个判定是否在范围内的函数:

1
2
def in_area(self, x, y):
return 0 <= x < self.m and 0 <= y < self.n

然后继续分析,这道题是要寻找一个坐标既能够到达太平洋也能到达大西洋,但是这个过程一般不是一次深度搜索就能够完成的,所以我们从各边界开始逆流进行搜索。然后用两个二维数组进行记录,相当于进行了4次深度搜索,具体答案可以参考答案

答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Solution:
def __init__(self):
self.result_all = None
# 分别表示上右下左
self.directs = [(-1, 0), (0, 1), (1, 0), (0, -1)]
self.m = 0
self.n = 0
# 表示能流到太平洋
self.po = None
# 表示能流到大西洋
self.ao = None
self.visited = None


def pacificAtlantic(self, matrix) :
# 初始化一些东西
self.result_all = []
self.m = len(matrix)
if self.m == 0:
return self.result_all
self.n = len(matrix[0])
self.ao = [[0] * self.n for _ in range(self.m)]
self.po = [[0] * self.n for _ in range(self.m)]
self.visited = [[0] * self.n for _ in range(self.m)]

# 本题顺着流不太好做,我们用逆流的方式来思考
# 从上面的太平洋逆流
for i in range(0, 1):
for j in range(self.n):
self.dfs(matrix, i, j, True)
# 从左边的太平洋逆流
self.visited = [[0] * self.n for _ in range(self.m)]
for i in range(self.m):
for j in range(0, 1):
self.dfs(matrix, i, j, True)
# 下面的大西洋
self.visited = [[0] * self.n for _ in range(self.m)]
for i in range(self.m - 1, self.m):
for j in range(self.n):
self.dfs(matrix, i, j, False)
# 右边的大西洋
self.visited = [[0] * self.n for _ in range(self.m)]
for i in range(self.m):
for j in range(self.n -1, self.n):
self.dfs(matrix, i, j, False)

for i in range(self.m):
for j in range(self.n):
if self.po[i][j] == 1 and self.ao[i][j] == 1:
self.result_all.append((i, j))
return self.result_all

def dfs(self, matrix, x, y, flag):
if self.visited[x][y] == 1:
return
self.visited[x][y] = 1
if flag:
# 表示是太平洋
self.po[x][y] = 1
else:
# 表示是大西洋
self.ao[x][y] = 1

for i in range(4):
newx = x + self.directs[i][0]
newy = y + self.directs[i][1]
if not self.in_area(newx, newy):
continue
if matrix[x][y] > matrix[newx][newy]:
continue
self.dfs(matrix, newx, newy, flag)
return

def in_area(self, x, y):
return 0 <= x < self.m and 0 <= y < self.n